{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Action1  使用MinHashLSHForest对微博新闻句子进行检索  weibo.txt     针对某句话进行Query，查找Top-3相似的句子     \n",
    "\n",
    "1、完成代码（30points）     \n",
    "\n",
    "2、使用MinHashLSHForest工具对MinHash进行index，并完成Query Top-K，代码正确（30points）  \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.feature_extraction.text import TfidfVectorizer\n",
    "import jieba.posseg as pseg\n",
    "import re"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 读取文件\n",
    "with open('./weibos.txt', 'r', encoding='UTF-8') as f:\n",
    "    text = f.read()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'#斯科拉里愿意执教国足#上一届如果是里皮从头芾到尾，是很大机会入世界杯的，这一届，没几个能用的，除非大力归化，谁来都没用。 \\u200b\\n国足输给叙利亚之后，里皮辞职。谁将成为新主帅，成为广大球迷关注的焦点。目前舆论方面，倾向于三个人：山东鲁能主帅李霄鹏、武汉卓尔主帅李铁、前广州恒大主帅斯科拉里。 \\u200b\\n据了解，无论中国足协态度如何，里皮其实在宣布请辞同时已经去意已决。据了解。比赛当晚，他的太太西蒙内塔女士及儿子小里皮都在现场看台上观战。辞职后的里皮没有改变原有的计划——赛后第二天他会从迪拜直接飞回意大利。这意味着，他本来也没打算与球队管理层或中国足协高层在赛后第一时间内进行有关辞职的对话。至于辞职以后的善后工作包括合同问题的沟通工作也要待日后双方进一步协商。\\n让我们回顾一下国足历届外籍教练——里皮，佩兰，卡马乔，杜伊科维奇，阿里·汉，米卢……。来之前一个比一个有名，来之后一个比一个水，国足踢不好完全是足协的问题，足协不解散重组，你把天王老子请来都不行\\n斯科拉里想执教中国国足！老头有点意思，凡是里皮干过的地方，他就想试试。当然，老头也是世界杯冠军教头，万一折在中国这里也没啥丢人的，毕竟里皮也折了嘛！可以试试！\\n斯科拉里的水平，还不如里皮。斯科拉里，看好的不是国足，而是年薪…… \\u200b\\n非常应该辞职！中国足球，不需要名帅，也不需要外籍教练，因为一点儿毛用也没有！从施拉普纳到现在，二十余年间，中国足球竟然大踏步的倒退，一点儿也杀不住车，奶奶的，刹车系统坏了！穿着几百块钱的球衣，几千块钱的球鞋，几万块钱的包，几十万的包机，几百万上千万的年薪\\n赛后，叙利亚主教练在更衣室里给每个队员一个耳光。主教练说：“赛前老子就再三交代，这一场无论如何都不能赢中国队！中国援助了我们那么多粮食和美金，如果他们不再援助我们国家，你狗日些要吃土去！”，球员委屈的说：“七十多分钟了，哪个晓得那个龟儿子往他们家球门踢嘛？”\\n里皮辞职返回意大利，他的助教马达洛尼随队返回广州。马达洛尼在接受采访时还原了当时更衣室中的情况：“当时在更衣室，球员们都过来试图说服里皮，让他收回决定，队长郑智尝试阻止他，足协的代表也希望他在考虑一下，我也建议他重新考虑，但无济于事。”\\n中国足协：接受里皮辞职请求，将深刻反思\\n看了个报道，马达洛尼说：“关于里皮的辞职，我事先也没有被告知，自己也不清楚发生了什么，也许是里皮头脑一热的决定。足协也可以留下我们，教练组所有成员都愿意留下，我们也可以和其他教练合作。” \\u200b\\n因为中国队给斯科拉里开足了薪水，给足了他需要的条件！尤其是最后一句话，看好中国队的潜力，这句话真是太鼓舞人心啦！ \\u200b带队结果绝不会比里皮更差， \\u200b而且我一定能带国足夺得2022世界杯冠军！大家支持斯科拉里不？ \\u200b\\n曾经也以为世界名帅里皮能够带领国足走出迷茫，让国足蒸蒸日上，也让我们国人不再迷茫，吃下一颗定心丸。现在我才知道，其实最应改变的不是教练，而是我们的国足，我们的训练机制、学习机制、培养机制。只有真正做好这些，才能使无论哪位名帅接手都能游刃有余地打好比赛。\\n国足输给叙利亚后，里皮坐不住了，直接辞职了\\n难怪有网友说，爱护生命，远离男足。男足的水平也就跟南极洲企鹅踢球。\\n足协主席赠书《红星照我去战斗》送给中国国脚，埃尔克森、里皮懂红色文化吗？\\n国足昨晚1-2输给叙利亚，赛后主帅里皮宣布辞职。'"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "text"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['斯科拉里愿意执教国足上一届如果是里皮从头芾到尾，是很大机会入世界杯的，这一届，没几个能用的，除非大力归化，谁来都没用',\n",
       " '国足输给叙利亚之后，里皮辞职',\n",
       " '谁将成为新主帅，成为广大球迷关注的焦点',\n",
       " '目前舆论方面，倾向于三个人：山东鲁能主帅李霄鹏、武汉卓尔主帅李铁、前广州恒大主帅斯科拉里',\n",
       " '据了解，无论中国足协态度如何，里皮其实在宣布请辞同时已经去意已决',\n",
       " '据了解',\n",
       " '比赛当晚，他的太太西蒙内塔女士及儿子小里皮都在现场看台上观战',\n",
       " '辞职后的里皮没有改变原有的计划——赛后第二天他会从迪拜直接飞回意大利',\n",
       " '这意味着，他本来也没打算与球队管理层或中国足协高层在赛后第一时间内进行有关辞职的对话',\n",
       " '至于辞职以后的善后工作包括合同问题的沟通工作也要待日后双方进一步协商',\n",
       " '让我们回顾一下国足历届外籍教练——里皮，佩兰，卡马乔，杜伊科维奇，阿里·汉，米卢……',\n",
       " '来之前一个比一个有名，来之后一个比一个水，国足踢不好完全是足协的问题，足协不解散重组，你把天王老子请来都不行斯科拉里想执教中国国足',\n",
       " '老头有点意思，凡是里皮干过的地方，他就想试试',\n",
       " '当然，老头也是世界杯冠军教头，万一折在中国这里也没啥丢人的，毕竟里皮也折了嘛',\n",
       " '可以试试',\n",
       " '斯科拉里的水平，还不如里皮',\n",
       " '斯科拉里，看好的不是国足，而是年薪……非常应该辞职',\n",
       " '中国足球，不需要名帅，也不需要外籍教练，因为一点儿毛用也没有',\n",
       " '从施拉普纳到现在，二十余年间，中国足球竟然大踏步的倒退，一点儿也杀不住车，奶奶的，刹车系统坏了',\n",
       " '穿着几百块钱的球衣，几千块钱的球鞋，几万块钱的包，几十万的包机，几百万上千万的年薪赛后，叙利亚主教练在更衣室里给每个队员一个耳光',\n",
       " '主教练说：“赛前老子就再三交代，这一场无论如何都不能赢中国队',\n",
       " '中国援助了我们那么多粮食和美金，如果他们不再援助我们国家，你狗日些要吃土去',\n",
       " '”，球员委屈的说：“七十多分钟了，哪个晓得那个龟儿子往他们家球门踢嘛',\n",
       " '”里皮辞职返回意大利，他的助教马达洛尼随队返回广州',\n",
       " '马达洛尼在接受采访时还原了当时更衣室中的情况：“当时在更衣室，球员们都过来试图说服里皮，让他收回决定，队长郑智尝试阻止他，足协的代表也希望他在考虑一下，我也建议他重新考虑，但无济于事',\n",
       " '”中国足协：接受里皮辞职请求，将深刻反思看了个报道，马达洛尼说：“关于里皮的辞职，我事先也没有被告知，自己也不清楚发生了什么，也许是里皮头脑一热的决定',\n",
       " '足协也可以留下我们，教练组所有成员都愿意留下，我们也可以和其他教练合作',\n",
       " '”因为中国队给斯科拉里开足了薪水，给足了他需要的条件',\n",
       " '尤其是最后一句话，看好中国队的潜力，这句话真是太鼓舞人心啦',\n",
       " '带队结果绝不会比里皮更差，而且我一定能带国足夺得2022世界杯冠军',\n",
       " '大家支持斯科拉里不',\n",
       " '曾经也以为世界名帅里皮能够带领国足走出迷茫，让国足蒸蒸日上，也让我们国人不再迷茫，吃下一颗定心丸',\n",
       " '现在我才知道，其实最应改变的不是教练，而是我们的国足，我们的训练机制、学习机制、培养机制',\n",
       " '只有真正做好这些，才能使无论哪位名帅接手都能游刃有余地打好比赛',\n",
       " '国足输给叙利亚后，里皮坐不住了，直接辞职了难怪有网友说，爱护生命，远离男足',\n",
       " '男足的水平也就跟南极洲企鹅踢球',\n",
       " '足协主席赠书《红星照我去战斗》送给中国国脚，埃尔克森、里皮懂红色文化吗',\n",
       " '国足昨晚1-2输给叙利亚，赛后主帅里皮宣布辞职']"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 以句号，叹号，问号作为分隔，去掉\\n换行符号、\\u200b、#、前后' '\n",
    "sentences = re.split('[。！？]', text.replace('\\n', '').replace('\\u200b','').replace('#','').replace(' ',''))\n",
    "# 最后一行如果为空，则删除\n",
    "if sentences[len(sentences)-1] == '':\n",
    "    sentences.pop()\n",
    "sentences"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "我 r\n",
      "爱 v\n",
      "北京 ns\n",
      "天安门 ns\n"
     ]
    }
   ],
   "source": [
    "# 将item_text进行分词，返回以空格连接的词\n",
    "import jieba\n",
    "def get_item_str(item_text):\n",
    "    item_str = \"\" \n",
    "    item=(pseg.cut(item_text)) \n",
    "    for i in list(item):\n",
    "        #去掉停用词，i.word取cut后的单词部分，不使用标注部分。如果jieba.cut，则不需要i.word属性了\n",
    "        if i.word not in list(stop):  \n",
    "            item_str += i.word\n",
    "            #tfidf_vectorizer.fit_transform的输入需要空格分隔的单词\n",
    "            item_str += \" \"\n",
    "    return item_str\n",
    "# import jieba.posseg as pseg 词性标注举例\n",
    "words = pseg.cut(\"我爱北京天安门\")\n",
    "for word, flag in words:\n",
    "    print('%s %s' % (word, flag))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 加载停用词表\n",
    "with open('chinese_stopwords.txt','r',encoding='utf-8') as file:\n",
    "    stopwords = [i[:-1] for i in file.readlines()]  # [:-1]取最后一个字符，目的是跳过\\n，防止取一行空一行\n",
    "# 设置停用词\n",
    "stop = [line.strip() for line in stopwords]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 使用jieba.cut分词而不是jieba.pseg.cut处理\n",
    "def split_text(text):\n",
    "    text2 = jieba.cut(text)\n",
    "    result = ' '.join([w for w in text2 if w not in stopwords])\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 得到分词后的documents\n",
    "documents = []\n",
    "for item_text in sentences:\n",
    "    # 将item_text进行分词\n",
    "    item_str = split_text(item_text)\n",
    "    documents.append(item_str)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['斯科拉里 愿意 执教 国足 一届 皮 从头 芾 尾 很大 机会 入 世界杯 一届 没 几个 能用 除非 大力 归化 没用',\n",
       " '国 足 输给 叙利亚 之后 皮 辞职',\n",
       " '成为 主帅 成为 广大 球迷 关注 焦点',\n",
       " '目前 舆论 方面 倾向 三个 山东鲁能 主帅 李霄鹏 武汉 卓尔 主帅 李铁 广州 恒大 主帅 斯科拉里',\n",
       " '了解 中国足协 态度 皮 其实 宣布 请辞 已经 去意 已决']"
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "documents[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [],
   "source": [
    "from datasketch import MinHash, MinHashLSH, MinHashLSHForest\n",
    "# 对item_str创建MinHash\n",
    "def get_minhash(item_str):\n",
    "    temp = MinHash()\n",
    "    for d in item_str:\n",
    "        temp.update(d.encode('utf8'))\n",
    "    return temp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建LSH Forest及MinHash对象\n",
    "minhash_list = []\n",
    "forest = MinHashLSHForest()\n",
    "for i in range(len(documents)):\n",
    "    #得到train_documents[i]的MinHash\n",
    "    # 将每一句转化为minihash值存放到minhash_list\n",
    "    temp = get_minhash(documents[i])\n",
    "    minhash_list.append(temp)\n",
    "    # 将索引0~len对应的minihash值加入forest\n",
    "    forest.add(i, temp)\n",
    "# index所有key，以便可以进行检索\n",
    "forest.index()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2 0.0703125 成为主帅成为广大球迷关注焦点\n",
      "34 0.2578125 国足输给叙利亚皮坐不住直接辞职难怪网友爱护生命远离男足\n",
      "35 0.2421875 男足水平南极洲企鹅踢球\n",
      "Top 3 邻居 [2, 34, 35]\n"
     ]
    }
   ],
   "source": [
    "query = '爱护生命，远离男足'\n",
    "# 将item_text进行分词\n",
    "item_str = split_text(query)\n",
    "# 得到item_str的MinHash\n",
    "minhash_query = get_minhash(item_str)\n",
    "\n",
    "# 查询forest中与m1相似的Top-K个邻居\n",
    "result = forest.query(minhash_query, 3)\n",
    "for i in range(len(result)):\n",
    "    print(result[i], minhash_query.jaccard(minhash_list[result[i]]), documents[result[i]].replace(' ', ''))\n",
    "print(\"Top 3 邻居\", result)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.8.0 64-bit ('Bi_env': venv)",
   "language": "python",
   "name": "python38064bitbienvvenvba07af95a1bb4b078aa8134bba84dff2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
